package com.quanyan.pay.component.weichat;

import com.quanyan.api.APIResponse;
import com.quanyan.common.enums.BaseEnum;
import com.quanyan.common.exception.BizException;
import com.quanyan.common.utils.GsonUtils;
import com.quanyan.common.utils.ObjectUtil;
import com.quanyan.common.utils.RandomStringGenerator;
import com.quanyan.pay.component.RespRefundMsg;
import com.quanyan.pay.exception.RespPayEnum;
import com.quanyan.weichat.api.WeichatServiceApi;
import com.quanyan.weichat.common.Configure;
import com.quanyan.weichat.common.Signature;
import com.quanyan.weichat.common.Util;
import com.quanyan.weichat.protocol.pay_protocol.AppPayData;
import com.quanyan.weichat.protocol.pay_protocol.H5PayReqData;
import com.quanyan.weichat.protocol.pay_protocol.WXScanPayReqData;
import com.quanyan.weichat.protocol.pay_protocol.WxScanCodePayReqData;
import com.quanyan.weichat.protocol.pay_status_query_protocal.PayStatusQueryReqData;
import com.quanyan.weichat.protocol.refund_query_protocol.RefundQueryReqData;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author songzj
 * @date 16/5/27-15:21
 */
@Component
public class WeiChatComponent {

    private Logger logger = LoggerFactory.getLogger(WeiChatComponent.class);

    /**
     * 微信APP支付
     *
     * @param appPayData
     * @return
     */
    public APIResponse<Map<String, String>> weichatAppProcess(AppPayData appPayData, Configure configure) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("appid", configure.getAppID());
        map.put("partnerid", configure.getMchID());
        APIResponse apiResponse=getPrepayId(appPayData);
        if(!apiResponse.isRet()){
            return APIResponse.returnFail(apiResponse.getErrmsg());
        }
        map.put("prepayid", apiResponse.getData().toString());
        map.put("package", "Sign=WXPay");  //IOS端要重新为package赋值.
        map.put("noncestr", RandomStringGenerator.getRandomStringByLength(32));
        map.put("timestamp", (System.currentTimeMillis() / 1000) + "");
        String sign = Signature.getSign(map, configure.getKey());
        map.put("sign", sign);
        map.put("packageValue", "Sign=WXPay");  //兼容安卓. package是java关键字.
        return APIResponse.returnSuccess(map);
    }


    /**
     * 微信H5支付
     *
     * @param h5PayReqData
     * @param configure
     * @return
     */
    public APIResponse<Map<String, String>> weichatH5Process(H5PayReqData h5PayReqData, Configure configure) {
        logger.warn(h5PayReqData.toString());
        logger.warn(configure.toString());
        Map<String, String> map = new HashMap<String, String>();
        map.put("appId", configure.getAppID());
        APIResponse apiResponse=getPrepayId(h5PayReqData);
        if(!apiResponse.isRet()){
            return APIResponse.returnFail(apiResponse.getErrmsg());
        }
        map.put("timeStamp", (System.currentTimeMillis() / 1000) + "");
        map.put("nonceStr", RandomStringGenerator.getRandomStringByLength(32));
        map.put("package", "prepay_id=" + apiResponse.getData().toString());
        map.put("signType", "MD5");
        String sign = Signature.getSign(map, configure.getKey());
        map.put("paySign", sign);
        return APIResponse.returnSuccess(map);
    }

    /**
     * 微信发起退款请求
     *
     * @return orderNo
     */
    public RespRefundMsg weichatRefundApply(Object requestData, Configure configure) {
        try {
            WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
            XStream xStream = new XStream(new DomDriver());
            xStream.alias("xml", requestData.getClass());
            String xml = xStream.toXML(requestData).replaceAll("__", "_");
            Map<String, String> rm = weichatServiceApi.userRefund(xml, configure.getCertData(), configure.getCertPassword());
            String returnCode = rm.get("return_code");//状态码
            String resultCode = rm.get("result_code");//接收申请成功.
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                logger.info("微信退款申请已成功提交至微信服务器。请求{}，晌应{}。", xml, GsonUtils.toJson(rm));
                return new RespRefundMsg(true, "提交退款申请成功!");
            } else {
                logger.info("微信退款申请提交至微信服务器异常。请求{}，晌应{}。", xml, GsonUtils.toJson(rm));
                return new RespRefundMsg(false, "WECHAT Response " + rm.get("err_code") + ":" + rm.get("err_code_des"));
            }
        } catch (Exception e) {
            Util.log(e);
            throw new BizException(e.getMessage());
        }
    }


    public Map<String, String> refundOrderStatusQuery(String orderNo, String refundNo, Configure configure) {
        try {
            WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
            RefundQueryReqData refundQueryReqData = new RefundQueryReqData(null, orderNo, refundNo, configure);
            return weichatServiceApi.userRefundQuery(ObjectUtil.objectToXMLString(refundQueryReqData));
        } catch (Exception e) {
            Util.log(e);
        }
        return null;
    }

    public Map<String, String> orderStatusQuery(String outTradeNo, String orderNo, Configure configure) {
        WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
        PayStatusQueryReqData payStatusQueryReqData = new PayStatusQueryReqData(outTradeNo, orderNo, configure);
        XStream xStream = new XStream(new DomDriver());
        xStream.alias("xml", payStatusQueryReqData.getClass());
        String xml = xStream.toXML(payStatusQueryReqData).replaceAll("__", "_");
        try {
            return weichatServiceApi.payOrderQuery(xml);
        } catch (Exception e) {
            Util.log(e);
        }
        return null;
    }

    private APIResponse<String> getPrepayId(Object o) {
        try {
            WeichatServiceApi api = new WeichatServiceApi();
            String xml = ObjectUtil.objectToXMLString(o);
            Map<String, String> origMap = api.userPrePay(xml);
            if (origMap == null || origMap.size() == 0) {
                return APIResponse.returnFail(RespPayEnum.WEICHAT_INTERNAL_SERVER_ERROR);
            }
            if (origMap.get("return_code").equals("FAIL")) {
                return APIResponse.returnFail(origMap.get("return_msg"));
            }
            return APIResponse.returnSuccess(origMap.get("prepay_id"));
        } catch (Exception e) {
            Util.log(e);
            return APIResponse.returnFail(e.getMessage());
        }
    }

    public APIResponse<Map<String, String>> weichatScanPay(WXScanPayReqData wxScanPayReqData, Configure configure) {
        Map<String, String> origMap = new HashMap<String, String>();
        try {
            WeichatServiceApi api = new WeichatServiceApi();
            String xml = ObjectUtil.objectToXMLString(wxScanPayReqData);
            origMap = api.weichatScanPay(xml);
            if (origMap == null || origMap.size() == 0) {
                return APIResponse.returnFail(RespPayEnum.WEICHAT_INTERNAL_SERVER_ERROR);
            }
            if (origMap.get("return_code").equals("SUCCESS")&&"FAIL".equals(origMap.get("result_code"))&&!origMap.get("err_code").equals("USERPAYING")) {
                return APIResponse.returnFail(origMap.get("err_code_des"));
            }
            if (origMap.get("return_code").equals("FAIL")) {
                return APIResponse.returnFail(origMap.get("return_msg"));
            }
            return APIResponse.returnSuccess(origMap);
        } catch (Exception e) {
            //出异常当有密支付，主动轮询接口，防止微信超时
            Util.log("调用微信扫描枪接口时："+e);
            origMap.put("result_code","FAIL");
            origMap.put("err_code","USERPAYING");
            return APIResponse.returnSuccess(origMap);
        }
    }

    public APIResponse<Map<String,String>> unifiedorder(WxScanCodePayReqData wxScanCodePayReqData) {
        try {
            WeichatServiceApi api = new WeichatServiceApi();
            String xml = ObjectUtil.objectToXMLString(wxScanCodePayReqData);
            Map<String, String> origMap = api.userPrePay(xml);
            if (origMap == null || origMap.size() == 0) {
                return APIResponse.returnFail(RespPayEnum.WEICHAT_INTERNAL_SERVER_ERROR);
            }
            if (origMap.get("return_code").equals("FAIL")) {
                return APIResponse.returnFail(origMap.get("return_msg"));
            }
            return APIResponse.returnSuccess(origMap);
        } catch (Exception e) {
            Util.log(e);
            return APIResponse.returnFail(e.getMessage());
        }
    }
}
